﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Publishing.Fields;
using WoltersKluwer.SPChainGang.Core.Constants;
using WoltersKluwer.SPChainGang.Core.Data.Entity;
using WoltersKluwer.SPChainGang.Core.Util;
using WoltersKluwer.SPChainGang.Core.ExtensionMethods;
using System.IO;

namespace WoltersKluwer.SPChainGang.Core.ObjectScanners
{
    class SiteListsScanner : ScannerBase //TODO: refactor this to use repository
    {
        public SiteListsScanner(SPSite targetSiteCollection, Guid configurationListId, JobMode mode, Guid jobId, string reportFolder, List<ConfigurationMapping> mappings)
            : base(targetSiteCollection, configurationListId, mode, jobId, reportFolder, mappings)
        {
        }

        public override void Scan(SPWeb web)
        {
            var siteUri = new Uri(web.Site.Url);
#if SOS
            Logger.Log(JobId, "SiteListsScanner Scan() web.Url={0}", web.Url);
#endif
            var lists = web.Lists;
            foreach (SPList list in lists)
            {
                try
                {
#if SOS
                    Logger.Log(JobId, "SiteListsScanner Scan() list={0} , list.BaseTemplate.ToString()={1}", list.DefaultViewUrl, list.BaseTemplate.ToString());
#endif
                    if (list == null || list.BaseTemplate == SPListTemplateType.UserInformation ||
                        (list.Title != null && list.Title.Equals("Long Running Operation Status")))
                    {
                        continue;
                    }

                    var items = list.Items;
                    var needToScanFiles = IsPublishingPages(list);
                    foreach (SPListItem item in items)
                    {
                        if (item == null) continue;
                        try
                        {
                            var needToScanFile = needToScanFiles && item.File != null;
#if SOS
                            Logger.Log(JobId, "SiteListsScanner Scan() item={0} needToScanFile={1}", item.Url,needToScanFile.ToString());
#endif
                            /* useless for now
                            var containsWebParts = item.ContentType != null &&
                                                   item.ContentType.Id == SPBuiltInContentTypeId.WebPartPage &&
                                                   IsAspxFile(item.File.Name);
                             */

                            Uri basePageUrl;
                            if (needToScanFile)
                            {
                                basePageUrl = new Uri(siteUri, item.File.ServerRelativeUrl);
                            }
                            else
                            {
                                var viewForm = list.Forms[PAGETYPE.PAGE_DISPLAYFORM];
                                basePageUrl = viewForm != null
                                                  ? new Uri(String.Format("{0}/{1}?ID={2}", web.Url, viewForm.Url,
                                                                          item.ID))
                                                  : new Uri(siteUri, item.Url);
                            }

                            ScanListFields(item, basePageUrl);
                            if (needToScanFile && IsAspxFile(item.File.Name))
                            {
#if SOS
                                    Logger.Log(JobId, "SiteListsScanner IsAspxFile");
#endif
                                ScanWebParts(item.File, basePageUrl, list.EnableVersioning);
                            }
                        }
                        catch (OutOfMemoryException)
                        {
                            throw;
                        }
                        catch (Exception e)
                        {
                            Logger.LogError(JobId,
                                            String.Format("Unable to scan item {0} in list {1}", item.Title,
                                                          list.DefaultViewUrl), e);
                        }
                    }
                }
                catch (OutOfMemoryException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    Logger.LogError(JobId, String.Format("Unable to scan list {0}", list.DefaultViewUrl), e);
                }
            }
        }

        private void ScanListFields(SPListItem item, Uri pageUri)
        {
#if SOS
            Logger.Log(JobId, "SiteListsScanner ScanListFields() item={0}", item.Url);
#endif
            var modify = OperationMode == JobMode.UpdateLinks;
            foreach (var field in from SPField field in item.Fields
                                  where field != null && !string.IsNullOrEmpty(field.Title)
                                  let itemTitle = item[field.Title]
                                  where itemTitle != null && !itemTitle.ToString().IsNullOrEmpty()
                                  select field)
            {
                try
                {
                    string newContent;
                    switch (field.TypeAsString)
                    {
                        case "HTML":
                            newContent = ProcessHtml(item[field.Title].ToString(), pageUri,
                                                     String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern,
                                                                   field.Title, "HTML"));
                            if (modify && NeedUpdate(newContent, item[field.Title].ToString()))
                            {
                                item[field.Title] = newContent;
                                item.SystemUpdate(false);
                            }
                            break;

                        case "Note":
                            var fieldAsMultiLineText = (SPFieldMultiLineText)field;
                            if (fieldAsMultiLineText.RichText)
                            {
                                newContent = ProcessHtml(
                                    item[field.Title].ToString(), pageUri,
                                    String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern, field.Title,
                                                  "Note - RichText"));
                                if (modify && NeedUpdate(newContent, item[field.Title].ToString()))
                                {
                                    item[field.Title] = newContent;
                                    item.SystemUpdate(false);
                                }
                            }
                            else
                            {
                                newContent = ProcessText(item[field.Title].ToString(), pageUri,
                                    String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern, field.Title, "Note"));
                                if (modify && NeedUpdate(newContent, item[field.Title].ToString()))
                                {
                                    item[field.Title] = newContent;
                                    item.SystemUpdate(false);
                                }
                            }
                            break;

                        case "Text":
                            newContent = ProcessText(item[field.Title].ToString(), pageUri,
                                String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern, field.Title, "Text"));
                            if (modify && NeedUpdate(newContent, item[field.Title].ToString()))
                            {
                                item[field.Title] = newContent;
                                item.SystemUpdate(false);
                            }
                            break;

                        case "URL":
                            var itemValue = new SPFieldUrlValue(item[field.Title].ToString());
                            var newUrl = ProcessLink(itemValue.Url, pageUri,
                                                     String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern,
                                                                   field.Title, "URL"));
                            if (modify && NeedUpdate(newUrl, itemValue.Url))
                            {
                                itemValue.Url = newUrl;
                                item[field.Title] = itemValue;
                                item.SystemUpdate(false);
                            }
                            break;

                        case "SummaryLinks":
                            var linksFieldValue = new SummaryLinkFieldValue(item[field.Title].ToString());
                            foreach (SummaryLink link in linksFieldValue.SummaryLinks)
                            {
                                try
                                {
                                    newContent = ProcessLink(link.LinkUrl, pageUri,
                                                             String.Format(GlobalConstants.ReportAdditionalInfoFieldPattern,
                                                                           field.Title, "SummaryLinks"));
                                    if (modify && NeedUpdate(newContent, link.LinkUrl))
                                    {
                                        int index = linksFieldValue.SummaryLinks.IndexOf(link);
                                        linksFieldValue.SummaryLinks[index].LinkUrl = newContent;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Logger.LogError(JobId, "Link process failed", ex);
                                }
                            }
                            if (modify)
                            {
                                item[field.Title] = linksFieldValue;
                                item.SystemUpdate(false);
                            }
                            break;
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(JobId,
                                    String.Format("Unable to process field {0} (type: {3}) in item {1} of the list {2}", field.Title,
                                                  item.ID, item.ParentList.DefaultViewUrl, field.TypeAsString), ex);
                }
            }
        }
    }
}
